import app
import sys
from PyQt5.QtWidgets import QApplication, QStackedWidget, QWidget, QMessageBox, QTableWidget, QTableWidgetItem
from PyQt5.QtGui import QIcon
from functools import partial
from cbjSqlFunc import MysqlConnector
from myLogger import MyLogger
from config import *


def print_backtrace(func):
    def wrapper(*args, **kwargs):
        try:
            args = args[:-1] if args[-1] == False else args
            ret = func(*args, **kwargs)
        except Exception as e:
            print(e.args, e.__traceback__, e.__cause__, e.__doc__, e.__context__)
        else:
            return ret

    return wrapper


class CampusCat:
    myUi: app.Ui_stackedWidget
    ui: QStackedWidget
    logger: MyLogger
    db: MysqlConnector
    userId: int
    permission: int
    tempData: dict

    def __init__(self):
        # 初始化基础成员
        self.logger = MyLogger(LOGPATH)
        self.db = MysqlConnector(host=HOST, user=USERNAME, password=PASSWORD, database=DATABASE,
                                 logger=self.logger)
        self.tempData = {}
        # 初始化UI界面
        application = QApplication(sys.argv)
        # 创建 StackedWidget 实例
        myUi = app.Ui_stackedWidget()
        # 创建窗口小部件
        ui = QStackedWidget()
        # 使用 setupUi 函数设置 StackedWidget 的布局和属性，并将 StackedWidget 添加到窗口小部件中
        myUi.setupUi(ui)
        # 设置图标和标题
        ui.setWindowIcon(QIcon('icon.ico'))
        ui.setWindowTitle("校园猫猫管理平台")
        # 创建关联
        # 登录界面
        myUi.login_pushButton_login.clicked.connect(self.onLogin)  # 不传参数调用
        myUi.login_pushButton_signup.clicked.connect(partial(self.onSwitchPage, myUi.page_signup))  # 传参数调用
        # 注册界面
        myUi.signup_pushButton_signup.clicked.connect(self.onSignup)
        myUi.signup_pushButton_return.clicked.connect(partial(self.onSwitchPage, myUi.page_login))
        # 菜单界面
        myUi.menu_pushButton_showCats.clicked.connect(self.onDisplayCats)
        myUi.menu_pushButton_showAppearance.clicked.connect(self.onDisplayAppearance)
        myUi.menu_pushButton_showFeed.clicked.connect(self.onDisplayFeed)
        myUi.menu_pushButton_addAppearance.clicked.connect(self.initPage_AddAppearance)
        myUi.menu_pushButton_addFeed.clicked.connect(self.initPage_AddFeed)
        myUi.menu_pushButton_addCat.clicked.connect(self.initPage_AddCat)
        # 猫猫位置打卡界面
        myUi.addAppearance_pushButton_commit.clicked.connect(self.onAddAppearance)
        myUi.addAppearance_pushButton_return.clicked.connect(partial(self.onSwitchPage, myUi.page_menu))
        # 猫猫喂食发卡界面
        myUi.addFeed_pushButton_commit.clicked.connect(self.onAddFeed)
        myUi.addFeed_pushButton_return.clicked.connect(partial(self.onSwitchPage, myUi.page_menu))
        # 添加猫猫界面
        myUi.addCat_pushButton_commit.clicked.connect(self.onAddCat)
        myUi.addCat_pushButton_return.clicked.connect(partial(self.onSwitchPage, myUi.page_menu))
        # 数据展示界面
        myUi.display_pushButton_return.clicked.connect(partial(self.onSwitchPage, myUi.page_menu))

        self.ui = ui
        self.myUi = myUi
        # 显示窗口
        ui.setCurrentWidget(myUi.page_login)
        ui.show()
        sys.exit(application.exec_())

    def onLogin(self):
        # 获取输入框内的数据
        data = {'username': self.myUi.login_lineEdit_username.text(),
                'password': self.myUi.login_lineEdit_password.text()}
        # 检查数据
        if data['username'] == '' or data['password'] == '':
            QMessageBox.critical(self.ui, "登录失败", "用户名密码不能为空", QMessageBox.Yes)
            return
        user_data = self.db.fetch(
            f"select `user_id`, `password`, `permission` from users where username='{data['username']}'")
        if user_data == () or user_data[0][1] != data['password']:
            QMessageBox.critical(self.ui, "登录失败", "用户名或密码错误", QMessageBox.Yes)
            self.logger.logger.warning(f"login failed: username: {data['username']}, password: {data['password']}")
            return
        # 登录成功
        QMessageBox.information(self.ui, "登录成功", "登录成功!", QMessageBox.Yes)
        self.onSwitchPage(self.myUi.page_menu)
        self.userId = user_data[0][0]
        self.permission = user_data[0][2]
        self.logger.logger.info(f"Successfully log in user: {data['username']}, user_id: {self.userId}")
        self.initData()

    def onSwitchPage(self, page: QWidget):
        self.ui.setCurrentWidget(page)

    def onSignup(self):
        # 获取输入框内的数据
        data = {'username': self.myUi.signup_lineEdit_username.text(),
                'password': self.myUi.signup_lineEdit_password.text(),
                'permission': 0,
                'email': self.myUi.signup_lineEdit_email.text(),
                'student_id': self.myUi.signup_lineEdit_studentID.text()}
        # 检查数据
        if data['username'] == '' or data['password'] == '':
            QMessageBox.critical(self.ui, "注册失败", "用户名密码不能为空", QMessageBox.Yes)
            return
        if self.db.fetch(f"select `password` from users where username='{data['username']}'") != ():
            QMessageBox.warning(self.ui, "注册", "用户名已被使用", QMessageBox.Yes)
            return
        if self.db.insertStr('users', data) != 1:
            QMessageBox.critical(self.ui, "注册失败", "SQL语句执行错误", QMessageBox.Yes)
            self.logger.logger.critical(f"signup Error in sql: {data}")
            return
        # 注册成功
        QMessageBox.information(self.ui, "注册完成", "注册成功!", QMessageBox.Yes)
        self.onSwitchPage(self.myUi.page_login)
        self.logger.logger.info(f"Successfully sign up user: {data['username']}")

    def initData(self):
        # 提前准备好cat和location, 因为它在多个地方被用到
        self.tempData['cats'] = self.db.fetch(f"select `cat_id`, `cat_name` from cat")
        self.tempData['locations'] = self.db.fetch(f"select `location_id`, `location_name` from location")

    def initPage_AddAppearance(self):
        self.onSwitchPage(self.myUi.page_addAppearance)
        self.myUi.addAppearance_comboBox_catName.clear()
        self.myUi.addAppearance_comboBox_location.clear()
        self.myUi.addAppearance_comboBox_catName.addItems([c[1] for c in self.tempData['cats']])
        self.myUi.addAppearance_comboBox_location.addItems([lo[1] for lo in self.tempData['locations']])

    @print_backtrace
    def onAddAppearance(self):
        # 获取数据
        cat_id = self.tempData['cats'][self.myUi.addAppearance_comboBox_catName.currentIndex()][0]
        location_id = self.tempData['locations'][self.myUi.addAppearance_comboBox_location.currentIndex()][0]
        desc = self.myUi.addAppearance_lineEdit_description.text()
        desc = 'NULL' if desc == '' else f"'{desc}'"
        # 插入数据
        self.db.execute(
            f"insert into appearance (user_id, cat_id, location_id, appearance_time, appearance_description) "
            f"values ({self.userId}, {cat_id}, {location_id}, NOW(), {desc})")
        QMessageBox.information(self.ui, "打卡成功", "猫猫位置打卡成功!", QMessageBox.Yes)

    @print_backtrace
    def initPage_AddFeed(self):
        self.onSwitchPage(self.myUi.page_addFeed)
        self.myUi.addFeed_comboBox_catName.clear()
        self.myUi.addFeed_comboBox_location.clear()
        self.myUi.addFeed_comboBox_catName.addItems([c[1] for c in self.tempData['cats']])
        self.myUi.addFeed_comboBox_location.addItems([lo[1] for lo in self.tempData['locations']])

    @print_backtrace
    def onAddFeed(self):
        # 获取数据
        food = self.myUi.addFeed_lineEdit_food.text()
        if food == '':
            QMessageBox.critical(self.ui, "打卡失败", "请选择食物", QMessageBox.Yes)
            return
        cat_id = self.tempData['cats'][self.myUi.addFeed_comboBox_catName.currentIndex()][0]  # 寻找对应的id
        location_id = self.tempData['locations'][self.myUi.addFeed_comboBox_location.currentIndex()][0]
        desc = self.myUi.addFeed_lineEdit_description.text()
        desc = 'NULL' if desc == '' else f"'{desc}'"
        # 插入数据
        self.db.execute(
            f"insert into feed (user_id, cat_id, location_id, food, feed_time, feed_description) "
            f"values ({self.userId}, {cat_id}, {location_id}, '{food}', NOW(), {desc})")
        QMessageBox.information(self.ui, "打卡成功", "猫猫喂食打卡成功!", QMessageBox.Yes)

    @print_backtrace
    def fillTableWidget(self, horizontalHeader: list[str], data: tuple[tuple]):
        """
        填充TableWidget表格
        :param horizontalHeader: 表格头
        :param data: 表格数据, 可以直接cursor.fetchall()从数据库中获取
        """
        table = self.myUi.display_tableWidget
        table.setColumnCount(len(horizontalHeader))  # 列数
        table.setRowCount(len(data))  # 行数
        table.setHorizontalHeaderLabels(horizontalHeader)  # 设置表头
        table.setEditTriggers(QTableWidget.NoEditTriggers)  # 只读表格
        # 插入数据
        for i, row in enumerate(data):
            for j, item in enumerate(row):
                # 处理数据
                item = str(item)
                item = '' if item == 'None' else item
                table.setItem(i, j, QTableWidgetItem(str(item)))
        table.resizeColumnsToContents()
        table.resizeRowsToContents()

    @print_backtrace
    def onDisplayCats(self):
        self.onSwitchPage(self.myUi.page_display)
        sql = f"select cat_name, breed_name, color_name, trait_name from cat_view"
        self.fillTableWidget(['猫猫名称', '猫猫品种', '猫猫颜色', '猫猫性格'], self.db.fetch(sql))

    @print_backtrace
    def onDisplayAppearance(self):
        self.onSwitchPage(self.myUi.page_display)
        sql = f"select cat_name, location_name, appearance_time, appearance_description " \
              f"from appearance_view order by appearance_time desc"
        self.fillTableWidget(['猫猫名称', '出现位置', '出现时间', '额外描述'], self.db.fetch(sql))

    @print_backtrace
    def onDisplayFeed(self):
        self.onSwitchPage(self.myUi.page_display)
        sql = f"select cat_name, username, location_name, food, feed_time, feed_description " \
              f"from feed_view order by feed_time desc"
        self.fillTableWidget(['猫猫名称', '喂食用户', '喂食位置', '食物', '喂食时间', '额外描述'], self.db.fetch(sql))

    @print_backtrace
    def initPage_AddCat(self):
        if self.permission != 1:
            # 非特权用户不允许访问
            QMessageBox.critical(self.ui, "选择失败", "您没有足够的权限", QMessageBox.Yes)
            return
        self.onSwitchPage(self.myUi.page_addCat)
        # 清空, 防止重复添加
        self.myUi.addCat_comboBox_breed.clear()
        self.myUi.addCat_comboBox_color.clear()
        self.myUi.addCat_comboBox_trait.clear()
        # 获取数据
        self.tempData['breed'] = self.db.fetch(f"select breed_id, breed_name from breed")
        self.tempData['color'] = self.db.fetch(f"select color_id, color_name from color")
        self.tempData['trait'] = self.db.fetch(f"select trait_id, trait_name from trait")
        # 添加数据
        self.myUi.addCat_comboBox_breed.addItems([d[1] for d in self.tempData['breed']])
        self.myUi.addCat_comboBox_color.addItems([d[1] for d in self.tempData['color']])
        self.myUi.addCat_comboBox_trait.addItems([d[1] for d in self.tempData['trait']])

    @print_backtrace
    def onAddCat(self):
        # 获取数据
        name = self.myUi.addCat_lineEdit_name.text()
        if name == "":
            QMessageBox.critical(self.ui, "添加失败", "猫猫昵称不能为空", QMessageBox.Yes)
            return
        breed_id = self.tempData['breed'][self.myUi.addCat_comboBox_breed.currentIndex()][0]
        color_id = self.tempData['color'][self.myUi.addCat_comboBox_color.currentIndex()][0]
        trait_id = self.tempData['trait'][self.myUi.addCat_comboBox_trait.currentIndex()][0]
        # 插入数据
        self.db.execute(
            f"insert into cat (breed_id, color_id, trait_id, cat_name) "
            f"values ({breed_id}, {color_id}, {trait_id}, '{name}')")
        QMessageBox.information(self.ui, "添加成功", "添加猫猫成功!", QMessageBox.Yes)
        # 刷新猫猫数据
        self.initData()


def main():
    try:
        CampusCat()
    except Exception as e:
        print(e.args, e.__traceback__)


if __name__ == '__main__':
    main()
